/*
 *  Copyright 2010 Wesley Gooch, Ryan Nix, Cody Wenzel.
 *  Montana State University - Spring Semester 2010
 *  Computer Science 450 - Compilers
 *  Project: Micro-Pascal Compiler
 */
package msu.compiler.scanner;

/**
 * 
 * @author Wesley Gooch
 */
public class Token {

    private byte type;
    private String lexeme = null;
    private int line;
    private int column;
    private String errorMessage = null;

    /**
     * Constructor for tokens that include a lexeme.
     * 98% of Tokens use this constructor.
     *
     * @param type    The byte comparator for this token type.
     * @param lexeme  The value string representing this token.
     * @param line     The line/line number for the starting char of this token.
     * @param column  The column number for the starting char of this token.
     */
    public Token(byte type, String lexeme, int line, int column) {
        this.type = type;
        this.lexeme = lexeme;
        this.line = line;
        this.column = column;
    }

    /**
     * Constructor for error tokens that do not have a lexeme. An error Message
     * Should be included to describe a lexical problem for error handling
     * later.
     *
     * @param type    The byte comparator for this error token type.
     * @param lexeme  The value string representing this token.
     * @param line     The line/line number for the starting char of this token.
     * @param column  The column number for the starting char of this token.
     * @param errorMessage The error message associated with this error token.
     */
    public Token(byte type, String lexeme, int line, int column, String errorMessage) {
        this.type = type;
        this.lexeme = lexeme;
        this.line = line;
        this.column = column;
        this.errorMessage = errorMessage;
    }

    public int getColumn() {
        return column;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public String getLexeme() {
        return lexeme;
    }

    public int getLine() {
        return line;
    }

    public byte getType() {
        return type;
    }

    @Override
    public String toString() {
        String message = "\"" + lexeme + "\" starts on line " +
                Integer.toString(line) + ", column " + Integer.toString(column) + ". ";
        if(type == MP_RUN_COMMENT || type == MP_RUN_STRING || type == MP_ERROR) {
            return "ERROR: " + errorMessage + " " + message;
        } else {
            return "Token: " + message;
        }
    }

    public String positionToString() {
        return " Line " +
                Integer.toString(line) + ", Column " +
                Integer.toString(column) + ".";
    }

    public static String getTypeString(byte type) {
        switch(type){
            case Token.MP_AND:
                return "MP_AND";
            case Token.MP_ASSIGN:
                return "MP_ASSIGN";
            case Token.MP_BEGIN:
                return "MP_BEGIN";
            case Token.MP_COLON:
                return "MP_COLON";
            case Token.MP_COMMA:
                return "MP_COMMA";
            case Token.MP_DIV:
                return "MP_DIV";
            case Token.MP_DO:
                return "MP_DO";
            case Token.MP_DOWNTO:
                return "MP_DOWNTO";
            case Token.MP_ELSE:
                return "MP_ELSE";
            case Token.MP_END:
                return "MP_END";
            case Token.MP_EOF:
                return "MP_EOF";
            case Token.MP_EQUAL:
                return "MP_EQUAL";
            case Token.MP_ERROR:
                return "MP_ERROR";
            case Token.MP_FIXED:
                return "MP_FIXED";
            case Token.MP_FIXED_LIT:
                return "MP_FIXED_LIT";
            case Token.MP_FLOAT:
                return "MP_FLOAT";
            case Token.MP_FLOAT_LIT:
                return "MP_FLOAT_LIT";
            case Token.MP_FOR:
                return "MP_FOR";
            case Token.MP_FUNCTION:
                return "MP_FUNCTION";
            case Token.MP_GEQUAL:
                return "MP_GEQUAL";
            case Token.MP_GTHAN:
                return "MP_GTHAN";
            case Token.MP_IDENTIFIER:
                return "MP_IDENTIFIER";
            case Token.MP_IF:
                return "MP_IF";
            case Token.MP_INTEGER:
                return "MP_INTEGER";
            case Token.MP_INTEGER_LIT:
                return "MP_INTEGER_LIT";
            case Token.MP_LEQUAL:
                return "MP_LEQUAL";
            case Token.MP_LPAREN:
                return "MP_LPAREN";
            case Token.MP_LTHAN:
                return "MP_LTHAN";
            case Token.MP_MINUS:
                return "MP_MINUS";
            case Token.MP_MOD:
                return "MP_MOD";
            case Token.MP_NEQUAL:
                return "MP_NEQUAL";
            case Token.MP_NOT:
                return "MP_NOT";
            case Token.MP_OR:
                return "MP_OR";
            case Token.MP_PERIOD:
                return "MP_PERIOD";
            case Token.MP_PLUS:
                return "MP_PLUS";
            case Token.MP_PROCEDURE:
                return "MP_PROCEDURE";
            case Token.MP_PROGRAM:
                return "MP_PROGRAM";
            case Token.MP_READ:
                return "MP_READ";
            case Token.MP_REPEAT:
                return "MP_REPEAT";
            case Token.MP_RPAREN:
                return "MP_RPAREN";
            case Token.MP_RUN_COMMENT:
                return "MP_RUN_COMMENT";
            case Token.MP_RUN_STRING:
                return "MP_RUN_STRING";
            case Token.MP_SCOLON:
                return "MP_SCOLON";
            case Token.MP_STRING_LIT:
                return "MP_STRING_LIT";
            case Token.MP_THEN:
                return "MP_THEN";
            case Token.MP_TIMES:
                return "MP_TIMES";
            case Token.MP_TO:
                return "MP_TO";
            case Token.MP_UNTIL:
                return "MP_UNTIL";
            case Token.MP_VAR:
                return "MP_VAR";
            case Token.MP_WHILE:
                return "MP_WHILE";
            case Token.MP_WRITE:
                return "MP_WRITE";
        }
        return("No type found");
    }

    // Static Finals Representing Token types.
    // Values are bytes for fastest possible compare times.
    // --------------------------------------------------
    // SYMBOL TYPES
    // --------------------------------------------------
    public final static byte MP_PERIOD = 0;    // "."
    public final static byte MP_COMMA = 1;    // ","
    public final static byte MP_SCOLON = 2;    // ";"
    public final static byte MP_LPAREN = 3;    // "("
    public final static byte MP_RPAREN = 4;    // ")"
    public final static byte MP_EQUAL = 5;    // "="
    public final static byte MP_GTHAN = 6;    // ">"
    public final static byte MP_GEQUAL = 7;    // ">="
    public final static byte MP_LTHAN = 8;    // "<"
    public final static byte MP_LEQUAL = 9;    // "<="
    public final static byte MP_NEQUAL = 10;   // "<>"
    public final static byte MP_ASSIGN = 11;   // ":="
    public final static byte MP_PLUS = 12;   // "+"
    public final static byte MP_MINUS = 13;   // "-"
    public final static byte MP_TIMES = 14;   // "*"
    public final static byte MP_COLON = 15;   // ":"
    // --------------------------------------------------
    // IDENTIFIER & LITERAL TYPES
    // --------------------------------------------------
    public final static byte MP_IDENTIFIER = 16;   // (letter | "_"(letter | digit)){["_"](letter | digit)}
    public final static byte MP_INTEGER_LIT = 17;   // digit{digit}
    public final static byte MP_FIXED_LIT = 18;   // digit{digit} "." digit{digit}
    public final static byte MP_FLOAT_LIT = 19;   // (digit{digit} | digit{digit} "." digit{digit}) ("e"|"E")["+"|"-"]digit{digit}
    public final static byte MP_STRING_LIT = 20;   // "'" {"''" | AnyCharacterExceptApostropheOrEOL} "'"
    // --------------------------------------------------
    // RESERVED WORD TYPES
    // --------------------------------------------------
    public final static byte MP_AND = 21;    // "and"
    public final static byte MP_BEGIN = 22;    // "begin"
    public final static byte MP_DIV = 23;    // "div"
    public final static byte MP_DO = 24;    // "do"
    public final static byte MP_DOWNTO = 25;    // "downto"
    public final static byte MP_ELSE = 26;    // "else"
    public final static byte MP_END = 27;    // "end"
    public final static byte MP_FIXED = 28;    // "fixed"
    public final static byte MP_FLOAT = 29;    // "float"
    public final static byte MP_FOR = 30;    // "for"
    public final static byte MP_FUNCTION = 31;    // "function"
    public final static byte MP_IF = 32;    // "if"
    public final static byte MP_INTEGER = 33;    // "integer"
    public final static byte MP_MOD = 34;    // "mod"
    public final static byte MP_NOT = 35;    // "not"
    public final static byte MP_OR = 36;    // "or"
    public final static byte MP_PROCEDURE = 37;    // "procedure"
    public final static byte MP_PROGRAM = 38;    // "program"
    public final static byte MP_READ = 39;    // "read"
    public final static byte MP_REPEAT = 40;    // "repeat"
    public final static byte MP_THEN = 41;    // "then"
    public final static byte MP_TO = 42;    // "to"
    public final static byte MP_UNTIL = 43;    // "until"
    public final static byte MP_VAR = 44;    // "var"
    public final static byte MP_WHILE = 45;    // "while"
    public final static byte MP_WRITE = 46;    // "write"
    // --------------------------------------------------
    // ERROR TYPES
    // --------------------------------------------------
    public final static byte MP_RUN_COMMENT = 47;
    public final static byte MP_RUN_STRING = 48;
    public final static byte MP_ERROR = 49;
    // --------------------------------------------------
    // OTHER TYPES
    // --------------------------------------------------
    public final static byte MP_EOF = 50;
}
